﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Caching;
using System.Globalization;
using SimpleModel.Cache.Redis;

namespace SimpleModel.Cache.Memory
{
    public class MemoryCacheService:ICacheService
    {
        private event EventHandler Signaled;
        private readonly string _keyPrefix;
        private readonly MemoryCache _cache = MemoryCache.Default;

        public MemoryCacheService(string keyPrefix)
        {
            if (string.IsNullOrEmpty(keyPrefix))
            {
                throw new ArgumentNullException("keyPrefix is null or empty");
            }
            this._keyPrefix = keyPrefix;
        }

        public object GetObject<T>(string key)
        {
            return _cache.Get(GetCompletedKey(key));
        }

        public void Put<T>(string key, T value)
        {
            _cache.Set(GetCompletedKey(key), value, GetCacheItemPolicy(ObjectCache.InfiniteAbsoluteExpiration));
        }

        public void Put<T>(string key, T value, TimeSpan validFor)
        {
            _cache.Set(GetCompletedKey(key), value, GetCacheItemPolicy(new DateTimeOffset(DateTime.Now.Add(validFor))));
        }

        public void Remove(string key)
        {
            _cache.Remove(GetCompletedKey(key));
        }

        public void Clear()
        {
            if (Signaled != null)
            {
                Signaled(null, EventArgs.Empty);
            }
        }

        private CacheItemPolicy GetCacheItemPolicy(DateTimeOffset absoluteExpiration)
        {
            var cacheItemPolicy = new CacheItemPolicy
            {
                AbsoluteExpiration = absoluteExpiration,
                SlidingExpiration = ObjectCache.NoSlidingExpiration
            };

            cacheItemPolicy.ChangeMonitors.Add(new TenantCacheClearMonitor(this));

            return cacheItemPolicy;
        }

        private string GetCompletedKey(string key)
        {
            return String.Concat(_keyPrefix, ":", key);
        }
        public class TenantCacheClearMonitor : ChangeMonitor
        {
            private readonly MemoryCacheService _storageService;

            private readonly string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
            public override string UniqueId
            {
                get { return _uniqueId; }
            }

            public TenantCacheClearMonitor(MemoryCacheService storageService)
            {
                _storageService = storageService;
                _storageService.Signaled += OnSignalRaised;
                InitializationComplete();
            }

            protected override void Dispose(bool disposing)
            {
                Dispose();
                _storageService.Signaled -= OnSignalRaised;
            }

            private void OnSignalRaised(object sender, EventArgs e)
            {
                OnChanged(null);
            }
        }
    }
    
}
